#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
租赁合同管理系统增强版模拟数据生成器

该模块提供全面的模拟测试数据生成功能，支持复杂配置、多样化业务场景、边界值和异常数据，
并确保数据间的关联性和逻辑性。适用于系统功能测试、性能测试和异常处理验证。

作者: AutoGenerator
版本: 2.0.0
日期: 2024-11-03
"""

import os
import sys
import time
import json
import random
import sqlite3
import argparse
import datetime
from typing import Dict, List, Optional, Any, Tuple, Callable, Set
from datetime import datetime as dt
from datetime import timedelta
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("mock_data_generator.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger(__name__)

# 确保可以导入系统的db_utils
if os.path.dirname(os.path.abspath(__file__)) not in sys.path:
    sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

try:
    from db_utils import DatabaseUtils
    HAS_SYSTEM_MODULES = True
except ImportError:
    HAS_SYSTEM_MODULES = False
    logger.warning("无法导入系统模块，将使用内置功能")


class EnhancedMockDataGenerator:
    """
    增强版模拟数据生成器，支持全面的测试数据生成需求
    """
    
    def __init__(self, db_path: str = None, config_path: str = None):
        """
        初始化增强版模拟数据生成器
        
        Args:
            db_path: 数据库文件路径，如果不提供则使用系统默认路径
            config_path: 配置文件路径，用于自定义数据生成规则
        """
        self.db_path = db_path or (DatabaseUtils.get_db_path() if HAS_SYSTEM_MODULES else "./lease_contract.db")
        self.config_path = config_path
        self.connection = None
        self.cursor = None
        
        # 初始化默认配置
        self.config = {
            'random_seed': None,  # 随机种子，用于可重复的测试
            'include_edge_cases': True,  # 是否包含边界值
            'include_exceptional_cases': True,  # 是否包含异常情况
            'clear_existing': False,  # 是否清除现有数据
            'batch_size': 1000,  # 批处理大小，优化大数据量生成性能
            
            # 数据生成数量配置
            'data_volumes': {
                'houses': 50,         # 房屋数量
                'tenants': 100,       # 租户数量
                'landlords': 10,      # 房东数量
                'contracts': 80,      # 合同数量
                'rent_records_per_contract': 3,  # 每个合同的租金记录数
                'notes': 20,          # 笔记数量
                'users': 5,           # 用户数量（新增）
                'system_params': 10,  # 系统参数数量（新增）
                'operation_logs': 100  # 操作日志数量（新增）
            },
            
            # 数据分布规则配置
            'distribution_rules': {
                'contract_status': {  # 合同状态分布
                    '执行中': 60,    # 60%
                    '已完成': 30,    # 30%
                    '已逾期': 10     # 10%
                },
                'payment_method': {  # 付款方式分布
                    '月付': 40,      # 40%
                    '季付': 30,      # 30%
                    '半年付': 20,    # 20%
                    '年付': 10       # 10%
                },
                'house_type': {  # 房屋类型分布
                    '住宅': 70,      # 70%
                    '商用': 20,      # 20%
                    '办公': 10       # 10%
                }
            },
            
            # 异常数据配置
            'exception_config': {
                'empty_values_ratio': 0.05,  # 空值比例
                'invalid_format_ratio': 0.03, # 格式错误比例
                'out_of_range_ratio': 0.02,   # 超出范围比例
                'duplicate_keys_ratio': 0.01  # 重复键比例
            }
        }
        
        # 加载配置文件（如果提供）
        if config_path and os.path.exists(config_path):
            self._load_config(config_path)
        
        # 预设数据
        self._setup_preset_data()
        
        # 记录已生成的唯一值
        self.generated_values = {
            'house_no': set(),
            'contract_no': set(),
            'tenant_id': set(),
            'note_name': set(),
            'username': set()
        }
    
    def _load_config(self, config_path: str):
        """
        从配置文件加载自定义配置
        
        Args:
            config_path: 配置文件路径
        """
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                custom_config = json.load(f)
                # 更新默认配置
                self._update_config_recursive(self.config, custom_config)
                logger.info(f"已从 {config_path} 加载自定义配置")
        except Exception as e:
            logger.error(f"加载配置文件失败: {str(e)}")
    
    def _update_config_recursive(self, original: Dict, update: Dict):
        """
        递归更新配置字典
        
        Args:
            original: 原始配置字典
            update: 要更新的配置字典
        """
        for key, value in update.items():
            if key in original and isinstance(original[key], dict) and isinstance(value, dict):
                self._update_config_recursive(original[key], value)
            else:
                original[key] = value
    
    def _setup_preset_data(self):
        """
        设置预设数据，用于生成更真实的模拟数据
        """
        # 房屋类型
        self.house_types = ['一室一厅', '两室一厅', '三室一厅', '三室两厅', '四室两厅', 
                          '公寓', '商铺', '办公楼', '仓库', '别墅', '酒店式公寓']
        
        # 房屋用途
        self.usage_types = ['住宅', '商用', '办公', '仓储', '混合', '教育', '医疗']
        
        # 房屋状态
        self.house_statuses = ['空闲', '已出租', '已预订', '维护中', '待装修', '已出售']
        
        # 合同状态
        self.contract_statuses = ['正常', '已到期', '已终止', '已续签', '即将到期', 
                                 '执行中', '已完成', '已逾期']
        
        # 付款方式
        self.payment_methods = ['月付', '季付', '半年付', '年付', '一次性付清']
        
        # 水电费计费方式
        self.utility_methods = ['按表计费', '固定费用', '全包']
        
        # 租金状态
        self.payment_statuses = ['未结清', '已结清', '部分结清', '已逾期']
        
        # 模拟城市区域
        self.city_districts = ['朝阳区', '海淀区', '东城区', '西城区', '丰台区', 
                             '石景山区', '通州区', '昌平区', '大兴区', '顺义区',
                             '房山区', '门头沟区', '怀柔区', '平谷区', '密云区', '延庆区']
        
        # 模拟街道
        self.streets = ['建国路', '中关村大街', '东单北大街', '西单北大街', '丰台路', 
                      '石景山路', '运河东路', '回龙观东大街', '黄村西大街', '顺义大街',
                      '朝阳路', '海淀区南大街', '东城区东四十条', '西城区金融街']
        
        # 模拟小区
        self.communities = ['阳光小区', '幸福家园', '和谐小区', '美好家园', '花园小区', 
                          '绿色家园', '未来城', '城市之光', '东方明珠', '金色年华',
                          '远洋天著', '保利香槟', '万科城市花园', '龙湖长楹天街', '首开璞瑅公馆']
        
        # 模拟楼栋号
        self.building_nums = [f'{i}号楼' for i in range(1, 21)] + \
                           [f'A{i}座' for i in range(1, 6)] + \
                           [f'B{i}座' for i in range(1, 6)]
        
        # 模拟房间号
        self.room_nums = [f'{i}{j}{k}' for i in range(1, 31) for j in range(1, 5) for k in range(1, 7)]
        
        # 模拟人名
        self.person_names = ['张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十',
                           '郑十一', '王十二', '刘十三', '陈十四', '杨十五', '黄十六',
                           '张A', '李B', '王C', '赵D', '钱E', '孙F', '周G', '吴H',
                           '张伟', '李娜', '王芳', '刘洋', '陈静', '杨磊', '黄强', '赵杰']
        
        # 模拟公司名称
        self.company_prefixes = ['北京', '上海', '广州', '深圳', '天津', '杭州', '南京',
                               '科技', '创新', '未来', '智慧', '绿色', '诚信', '卓越']
        
        self.company_suffixes = ['科技有限公司', '置业有限公司', '物业管理有限公司', 
                               '房产经纪有限公司', '贸易有限公司', '投资有限公司',
                               '咨询有限公司', '服务有限公司']
        
        # 银行账户
        self.bank_accounts = ['招商银行', '建设银行', '工商银行', '中国银行', '农业银行', 
                            '交通银行', '邮储银行', '中信银行', '民生银行', '浦发银行',
                            '支付宝', '微信支付']
        
        # 操作日志类型
        self.operation_types = ['登录', '登出', '新增', '编辑', '删除', '查询', '导出', 
                              '导入', '设置修改', '权限变更', '数据备份', '数据恢复']
        
        # 系统参数键名
        self.system_param_keys = ['db_version', 'last_backup', 'system_name', 'max_file_size',
                                'backup_interval_days', 'log_retention_days', 'max_users',
                                'session_timeout_minutes', 'max_contracts_per_page', 
                                'default_currency']
    
    def connect(self) -> bool:
        """
        连接到数据库
        
        Returns:
            bool: 是否连接成功
        """
        try:
            # 对于大数据量，启用内存临时表和写同步优化
            self.connection = sqlite3.connect(
                self.db_path,
                isolation_level='EXCLUSIVE'  # 使用独占事务提高性能
            )
            self.cursor = self.connection.cursor()
            
            # 启用性能优化
            self.cursor.execute("PRAGMA synchronous = OFF")  # 批量导入时提高性能
            self.cursor.execute("PRAGMA journal_mode = MEMORY")  # 内存日志模式
            
            logger.info(f"成功连接到数据库: {self.db_path}")
            
            # 设置随机种子（如果提供）
            if self.config['random_seed'] is not None:
                random.seed(self.config['random_seed'])
                logger.info(f"已设置随机种子: {self.config['random_seed']}")
            
            # 如果需要清除现有数据
            if self.config['clear_existing']:
                self._clear_existing_data()
            
            return True
        except Exception as e:
            logger.error(f"连接数据库失败: {str(e)}")
            return False
    
    def disconnect(self):
        """
        断开数据库连接
        """
        try:
            if self.connection:
                # 恢复默认设置
                self.cursor.execute("PRAGMA synchronous = FULL")
                self.cursor.execute("PRAGMA journal_mode = DELETE")
                self.connection.close()
                logger.info("数据库连接已关闭")
        except Exception as e:
            logger.error(f"关闭数据库连接失败: {str(e)}")
    
    def _clear_existing_data(self):
        """
        清除现有的测试数据，但保留关键的默认数据
        """
        try:
            logger.info("开始清除现有测试数据...")
            
            # 需要清除数据的表（按依赖关系排序）
            tables_to_clear = [
                'operation_logs',  # 独立表
                'rent_records',    # 依赖contracts
                'contracts',       # 依赖houses和tenants
                'notes',           # 独立表
                'houses',          # 独立表
                'tenants',         # 独立表
                'landlords',       # 独立表
                'users'            # 独立表，但保留默认管理员
            ]
            
            for table in tables_to_clear:
                try:
                    # 对于users表，只删除非管理员用户
                    if table == 'users':
                        self.cursor.execute("DELETE FROM users WHERE username != 'admin'")
                    else:
                        self.cursor.execute(f"DELETE FROM {table}")
                    self.connection.commit()
                    logger.info(f"已清除表 {table} 的数据")
                except Exception as e:
                    logger.warning(f"清除表 {table} 数据失败: {str(e)}")
                    self.connection.rollback()
            
            # 重置已生成值记录
            for key in self.generated_values:
                self.generated_values[key].clear()
        
        except Exception as e:
            logger.error(f"清除数据过程中发生错误: {str(e)}")
            if self.connection:
                self.connection.rollback()
    
    def generate_mock_data(self, custom_config: Dict[str, Any] = None) -> bool:
        """
        根据配置生成模拟数据
        
        Args:
            custom_config: 自定义配置参数，将覆盖默认配置
                例如: {
                    'data_volumes': {
                        'houses': 100,
                        'tenants': 200
                    },
                    'include_edge_cases': True
                }
        
        Returns:
            bool: 是否生成成功
        """
        try:
            # 更新配置
            if custom_config:
                self._update_config_recursive(self.config, custom_config)
            
            if not self.connect():
                return False
            
            logger.info("开始生成模拟数据...")
            
            # 记录开始时间
            start_time = time.time()
            
            # 生成顺序按照依赖关系：先生成被引用的表
            self._generate_house_types()
            self._generate_landlords(self.config['data_volumes']['landlords'])
            self._generate_houses(self.config['data_volumes']['houses'])
            self._generate_tenants(self.config['data_volumes']['tenants'])
            self._generate_users(self.config['data_volumes']['users'])
            self._generate_contracts(self.config['data_volumes']['contracts'])
            self._generate_rent_records(self.config['data_volumes']['rent_records_per_contract'])
            self._generate_notes(self.config['data_volumes']['notes'])
            self._generate_system_params(self.config['data_volumes']['system_params'])
            self._generate_operation_logs(self.config['data_volumes']['operation_logs'])
            
            # 提交所有更改
            self.connection.commit()
            
            # 记录完成时间
            elapsed_time = time.time() - start_time
            logger.info(f"模拟数据生成完成并已保存到数据库，耗时: {elapsed_time:.2f} 秒")
            
            # 生成数据统计报告
            self._generate_data_report()
            
            return True
            
        except Exception as e:
            logger.error(f"生成模拟数据时发生错误: {str(e)}", exc_info=True)
            if self.connection:
                self.connection.rollback()
            return False
        finally:
            self.disconnect()
    
    def _generate_house_types(self):
        """
        生成房屋类型及其对应的水电费标准
        """
        try:
            logger.info("生成房屋类型及水电费标准...")
            
            # 检查是否已有数据
            self.cursor.execute("SELECT COUNT(*) FROM utility_fee")
            if self.cursor.fetchone()[0] > 0:
                if not self.config['clear_existing']:
                    logger.info("utility_fee表已有数据，跳过生成")
                    return
            
            # 为每种房屋类型生成水电费标准
            for house_type in self.house_types:
                # 根据房屋类型确定不同的水电费率
                if '商铺' in house_type or '办公' in house_type:
                    water_fee = round(random.uniform(8.0, 12.0), 2)
                    electricity_fee = round(random.uniform(1.5, 2.5), 2)
                else:
                    water_fee = round(random.uniform(4.0, 7.0), 2)
                    electricity_fee = round(random.uniform(0.5, 1.0), 2)
                
                # 添加边界值
                if self.config['include_edge_cases'] and random.random() < self.config['exception_config']['empty_values_ratio']:
                    water_fee = 0  # 免费
                
                # 添加异常值
                if self.config['include_exceptional_cases'] and random.random() < self.config['exception_config']['out_of_range_ratio']:
                    water_fee = round(random.uniform(100.0, 500.0), 2)  # 极高的费用
                    electricity_fee = round(random.uniform(10.0, 20.0), 2)
                
                try:
                    self.cursor.execute(
                        "INSERT OR REPLACE INTO utility_fee (house_type, water_fee, electricity_fee) VALUES (?, ?, ?)",
                        (house_type, water_fee, electricity_fee)
                    )
                except Exception as e:
                    logger.warning(f"插入房屋类型 {house_type} 失败: {str(e)}")
            
            logger.info(f"已生成 {len(self.house_types)} 种房屋类型及水电费标准")
            
        except Exception as e:
            logger.error(f"生成房屋类型数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_landlords(self, count: int):
        """
        生成房东数据
        
        Args:
            count: 房东数量
        """
        try:
            logger.info(f"生成 {count} 个房东数据...")
            
            created_count = 0
            
            for i in range(count):
                # 根据分布规则决定是公司还是个人
                is_company = random.random() > 0.3  # 70%为公司
                
                if is_company:
                    landlord_name = f"{random.choice(self.company_prefixes)}{random.choice(self.company_suffixes)}"
                    legal_representative = random.choice(self.person_names)
                    person_in_charge = random.choice(self.person_names)
                else:
                    landlord_name = random.choice(self.person_names)
                    legal_representative = None
                    person_in_charge = None
                
                # 生成联系电话
                contact_phone = self._generate_phone_number()
                
                # 生成地址
                address = f"{random.choice(self.city_districts)}{random.choice(self.streets)}{random.randint(1, 100)}号"
                
                # 设置默认房东（第一个为默认）
                is_default = 1 if i == 0 else 0
                
                # 添加异常数据
                if self.config['include_edge_cases'] and random.random() < self.config['exception_config']['empty_values_ratio']:
                    contact_phone = ""
                
                if self.config['include_exceptional_cases'] and random.random() < self.config['exception_config']['invalid_format_ratio']:
                    landlord_name = "测试异常_!@#$%^&*()"
                    contact_phone = "abcdefg"  # 无效电话号码格式
                
                try:
                    self.cursor.execute(
                        "INSERT INTO landlords (landlord_name, legal_representative, person_in_charge, contact_phone, is_default) VALUES (?, ?, ?, ?, ?)",
                        (landlord_name, legal_representative, person_in_charge, contact_phone, is_default)
                    )
                    created_count += 1
                except Exception as e:
                    logger.warning(f"插入房东数据失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 个房东数据")
            
        except Exception as e:
            logger.error(f"生成房东数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_houses(self, count: int):
        """
        生成房屋数据
        
        Args:
            count: 房屋数量
        """
        try:
            logger.info(f"生成 {count} 个房屋数据...")
            
            created_count = 0
            batch_data = []
            
            for i in range(count):
                # 生成唯一的房屋编号
                house_no = self._generate_unique_value('house_no', lambda: f"F{random.randint(10000, 99999)}")
                
                # 生成房屋位置
                district = random.choice(self.city_districts)
                street = random.choice(self.streets)
                community = random.choice(self.communities)
                building = random.choice(self.building_nums)
                room = random.choice(self.room_nums)
                
                house_location = f"{district}{street}{community}{building}{room}"
                
                # 根据分布规则选择房屋类型
                house_type = self._weighted_random_choice(self.config['distribution_rules']['house_type'], 
                                                       fallback_list=self.house_types)
                
                # 根据房屋类型确定面积范围
                if '一室' in house_type:
                    min_area, max_area = 30, 60
                elif '两室' in house_type:
                    min_area, max_area = 50, 90
                elif '三室' in house_type:
                    min_area, max_area = 80, 130
                elif '四室' in house_type:
                    min_area, max_area = 120, 180
                elif '公寓' in house_type:
                    min_area, max_area = 20, 50
                elif '商铺' in house_type:
                    min_area, max_area = 40, 200
                elif '办公' in house_type:
                    min_area, max_area = 60, 300
                elif '仓库' in house_type:
                    min_area, max_area = 100, 1000
                elif '别墅' in house_type:
                    min_area, max_area = 150, 300
                else:
                    min_area, max_area = 50, 120
                
                house_area = round(random.uniform(min_area, max_area), 2)
                
                # 生成用途和状态
                usage = random.choice(self.usage_types)
                status = random.choice(self.house_statuses)
                
                # 添加边界值
                if self.config['include_edge_cases'] and random.random() < self.config['exception_config']['empty_values_ratio']:
                    house_area = 0.1  # 极小面积
                
                # 添加异常值
                if self.config['include_exceptional_cases'] and random.random() < self.config['exception_config']['out_of_range_ratio']:
                    house_area = 9999.99  # 极大面积
                    house_location = "地址超长" * 20  # 超长地址
                
                # 添加到批处理数据
                batch_data.append((house_no, house_location, house_area, house_type, usage))
                
                # 批量插入
                if len(batch_data) >= self.config['batch_size']:
                    try:
                        self.cursor.executemany(
                            "INSERT INTO houses (house_no, house_location, house_area, house_type, usage) VALUES (?, ?, ?, ?, ?)",
                            batch_data
                        )
                        created_count += len(batch_data)
                        batch_data = []
                    except Exception as e:
                        logger.warning(f"批量插入房屋数据失败: {str(e)}")
            
            # 插入剩余数据
            if batch_data:
                try:
                    self.cursor.executemany(
                        "INSERT INTO houses (house_no, house_location, house_area, house_type, usage) VALUES (?, ?, ?, ?, ?)",
                        batch_data
                    )
                    created_count += len(batch_data)
                except Exception as e:
                    logger.warning(f"插入剩余房屋数据失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 个房屋数据")
            
        except Exception as e:
            logger.error(f"生成房屋数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_tenants(self, count: int):
        """
        生成租户数据
        
        Args:
            count: 租户数量
        """
        try:
            logger.info(f"生成 {count} 个租户数据...")
            
            created_count = 0
            batch_data = []
            
            for i in range(count):
                # 随机生成个人或公司租户
                is_company = random.random() > 0.6  # 40%为公司
                
                if is_company:
                    tenant_name = f"{random.choice(self.company_prefixes)}{random.choice(self.company_suffixes)}{random.randint(1, 100)}"
                    contact_person = random.choice(self.person_names)
                    # 公司使用统一社会信用代码格式
                    contact_id = self._generate_unique_value('tenant_id', 
                                                           lambda: f"{random.randint(10000000, 99999999)}" + 
                                                                   f"{random.randint(0, 9)}{random.randint(0, 9)}" + 
                                                                   f"{random.choice('QWERTYUIOPASDFGHJKLZXCVBNM')}")
                else:
                    tenant_name = random.choice(self.person_names)
                    contact_person = tenant_name  # 个人租户联系人就是自己
                    # 个人使用身份证号码格式
                    contact_id = self._generate_unique_value('tenant_id', 
                                                           lambda: f"{random.randint(110000, 999999)}" + 
                                                                   f"{random.randint(1950, 2000):04d}" + 
                                                                   f"{random.randint(1, 12):02d}{random.randint(1, 28):02d}" + 
                                                                   f"{random.randint(100, 999)}{random.choice('0123456789X')}")
                
                # 生成联系电话
                contact_phone = self._generate_phone_number()
                
                # 添加边界值
                if self.config['include_edge_cases'] and random.random() < self.config['exception_config']['empty_values_ratio']:
                    contact_phone = ""  # 空电话号码
                
                # 添加异常值
                if self.config['include_exceptional_cases'] and random.random() < self.config['exception_config']['invalid_format_ratio']:
                    contact_id = "111111111111111111"  # 无效身份证
                    contact_phone = "123"  # 无效电话
                
                # 添加到批处理数据
                batch_data.append((tenant_name, contact_person, contact_id, contact_phone))
                
                # 批量插入
                if len(batch_data) >= self.config['batch_size']:
                    try:
                        self.cursor.executemany(
                            "INSERT INTO tenants (tenant_name, contact_person, contact_id, contact_phone) VALUES (?, ?, ?, ?)",
                            batch_data
                        )
                        created_count += len(batch_data)
                        batch_data = []
                    except Exception as e:
                        logger.warning(f"批量插入租户数据失败: {str(e)}")
            
            # 插入剩余数据
            if batch_data:
                try:
                    self.cursor.executemany(
                        "INSERT INTO tenants (tenant_name, contact_person, contact_id, contact_phone) VALUES (?, ?, ?, ?)",
                        batch_data
                    )
                    created_count += len(batch_data)
                except Exception as e:
                    logger.warning(f"插入剩余租户数据失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 个租户数据")
            
        except Exception as e:
            logger.error(f"生成租户数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_users(self, count: int):
        """
        生成用户数据（新增功能）
        
        Args:
            count: 用户数量
        """
        try:
            logger.info(f"生成 {count} 个用户数据...")
            
            # 角色列表
            roles = ['管理员', '操作员', '查看员']
            
            created_count = 0
            
            # 导入密码工具类
            try:
                from user_auth import PasswordUtils
                use_password_utils = True
            except ImportError:
                use_password_utils = False
                logger.warning("无法导入密码工具类，将使用简单密码")
            
            for i in range(count):
                # 生成唯一的用户名
                username = self._generate_unique_value('username', 
                                                     lambda: f"{random.choice(self.person_names).lower()}{random.randint(10, 99)}")
                
                # 生成密码
                if use_password_utils:
                    password = PasswordUtils.hash_password('password123')
                else:
                    password = 'password123'  # 开发环境使用简单密码
                
                # 随机选择角色
                role = random.choice(roles)
                
                try:
                    self.cursor.execute(
                        "INSERT INTO users (username, password, role) VALUES (?, ?, ?)",
                        (username, password, role)
                    )
                    created_count += 1
                except Exception as e:
                    logger.warning(f"插入用户数据失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 个用户数据")
            
        except Exception as e:
            logger.error(f"生成用户数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_contracts(self, count: int):
        """
        生成合同数据
        
        Args:
            count: 合同数量
        """
        try:
            logger.info(f"生成 {count} 个合同数据...")
            
            # 获取现有的房源和租户
            self.cursor.execute("SELECT id, house_no, house_location, house_area, house_type, usage FROM houses")
            houses = self.cursor.fetchall()
            
            self.cursor.execute("SELECT id, tenant_name, contact_person, contact_id, contact_phone FROM tenants")
            tenants = self.cursor.fetchall()
            
            self.cursor.execute("SELECT id, landlord_name, legal_representative, person_in_charge, contact_phone FROM landlords")
            landlords = self.cursor.fetchall()
            
            if not houses or not tenants or not landlords:
                logger.error("无法生成合同数据，缺少必要的房屋、租户或房东数据")
                return
            
            created_count = 0
            batch_data = []
            # 跟踪已使用的房屋ID，以确保一个房屋在同一时间只有一个有效合同
            used_houses = set()
            
            for i in range(count):
                # 生成唯一的合同编号
                contract_no = self._generate_unique_value('contract_no', 
                                                        lambda: f"HT{random.randint(2020, 2024)}{random.randint(1, 12):02d}{random.randint(1000, 9999)}")
                
                # 选择一个随机的房东
                landlord = random.choice(landlords)
                
                # 选择一个未被使用的房屋或有一定概率重复使用（模拟到期后重新出租）
                reuse_house = random.random() < 0.1  # 10%的概率重用房屋
                
                if not reuse_house and len(used_houses) < len(houses):
                    # 尝试找到未使用的房屋
                    available_houses = [h for h in houses if h[0] not in used_houses]
                    if available_houses:
                        house = random.choice(available_houses)
                        used_houses.add(house[0])
                    else:
                        # 所有房屋都已使用，随机选择一个
                        house = random.choice(houses)
                else:
                    house = random.choice(houses)
                
                # 选择一个随机的租户
                tenant = random.choice(tenants)
                
                # 生成签约日期
                sign_date = (dt.now() - timedelta(days=random.randint(1, 1095))).strftime("%Y-%m-%d")
                sign_year_month = sign_date[:7]  # YYYY-MM格式
                
                # 生成合同开始日期（通常在签约日期之后或当天）
                start_date = (dt.strptime(sign_date, "%Y-%m-%d") + timedelta(days=random.randint(0, 30))).strftime("%Y-%m-%d")
                
                # 生成合同结束日期（通常为1-5年）
                contract_years = random.randint(1, 5)
                end_date = (dt.strptime(start_date, "%Y-%m-%d") + timedelta(days=contract_years*365)).strftime("%Y-%m-%d")
                
                # 根据分布规则确定合同状态
                status = self._weighted_random_choice(self.config['distribution_rules']['contract_status'], 
                                                    fallback_list=['执行中', '已完成', '已逾期'])
                
                # 根据状态调整日期（确保状态与日期逻辑一致）
                today = dt.now().strftime("%Y-%m-%d")
                if status == '已完成' or status == '已逾期':
                    if end_date > today:  # 如果结束日期在未来，则调整为过去
                        end_date = (dt.now() - timedelta(days=random.randint(1, 365))).strftime("%Y-%m-%d")
                elif status == '执行中':
                    if end_date < today:  # 如果结束日期在过去，则调整为未来
                        end_date = (dt.now() + timedelta(days=random.randint(1, 365))).strftime("%Y-%m-%d")
                
                # 根据分布规则选择付款方式
                payment_method = self._weighted_random_choice(self.config['distribution_rules']['payment_method'], 
                                                            fallback_list=self.payment_methods)
                
                # 根据房屋面积和类型计算月租
                base_rent_per_sqm = 0
                if '商铺' in house[4] or '办公' in house[4]:
                    base_rent_per_sqm = random.uniform(10, 30)
                else:
                    base_rent_per_sqm = random.uniform(5, 20)
                
                house_area = house[3]  # 已经是float类型
                monthly_rent = int(base_rent_per_sqm * house_area)
                # 确保月租金不为0
                if monthly_rent <= 0:
                    monthly_rent = 100  # 设置一个合理的最小值
                
                quarterly_rent = int(monthly_rent * 3) if payment_method in ['季付', '半年付', '年付'] else None
                annual_rent = int(monthly_rent * 12)
                total_rent = int(annual_rent * contract_years)
                
                # 押金通常为1-3个月房租
                deposit = int(monthly_rent * random.randint(1, 3))
                
                # 水电费计费方式
                utility_method = random.choice(self.utility_methods)
                
                # 如果是固定费用，设置水电费用
                water_fee = None
                electricity_fee = None
                if utility_method == '固定费用':
                    water_fee = round(random.uniform(100, 500), 2)
                    electricity_fee = round(random.uniform(200, 1000), 2)
                
                # 备注
                remarks = None
                if random.random() < 0.2:
                    remarks = f"合同备注: {random.randint(1, 100)}"
                
                # 添加边界值
                if self.config['include_edge_cases'] and random.random() < self.config['exception_config']['empty_values_ratio']:
                    monthly_rent = max(100, monthly_rent // 10)  # 确保最小值为100，而不是1
                    # 重新计算相关租金
                    quarterly_rent = int(monthly_rent * 3) if payment_method in ['季付', '半年付', '年付'] else None
                    annual_rent = int(monthly_rent * 12)
                    total_rent = int(annual_rent * contract_years)
                
                # 添加异常值
                if self.config['include_exceptional_cases'] and random.random() < self.config['exception_config']['out_of_range_ratio']:
                    # 限制极高租金的范围，避免后续生成租金记录时出现不合理情况
                    monthly_rent = min(99999, int(monthly_rent * random.uniform(1.5, 3.0)))
                    # 重新计算相关租金
                    quarterly_rent = int(monthly_rent * 3) if payment_method in ['季付', '半年付', '年付'] else None
                    annual_rent = int(monthly_rent * 12)
                    total_rent = int(annual_rent * contract_years)
                    end_date = (dt.now() - timedelta(days=10)).strftime("%Y-%m-%d")  # 已过期
                
                # 添加到批处理数据
                batch_data.append((
                    contract_no, sign_date, sign_year_month, house[1], house[2], house[3],
                    landlord[1], landlord[2], landlord[3], landlord[4],
                    tenant[1], tenant[1], tenant[3], tenant[4],
                    start_date, end_date, status, payment_method,
                    monthly_rent, quarterly_rent, total_rent, annual_rent, deposit,
                    house[5], utility_method, water_fee, electricity_fee, remarks
                ))
                
                # 批量插入
                if len(batch_data) >= self.config['batch_size']:
                    try:
                        self.cursor.executemany(
                            '''INSERT INTO contracts 
                            (contract_no, sign_date, sign_year_month, house_no, house_location, house_area, 
                            lessor, legal_representative, person_in_charge, contact_phone, 
                            lessee, tenant, tenant_id, tenant_phone, 
                            start_date, end_date, status, payment_method, 
                            monthly_rent, quarterly_rent, total_rent, annual_rent, deposit, 
                            usage, utility_method, water_fee, electricity_fee, remarks) 
                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
                            batch_data
                        )
                        created_count += len(batch_data)
                        batch_data = []
                    except Exception as e:
                        logger.warning(f"批量插入合同数据失败: {str(e)}")
            
            # 插入剩余数据
            if batch_data:
                try:
                    self.cursor.executemany(
                        '''INSERT INTO contracts 
                        (contract_no, sign_date, sign_year_month, house_no, house_location, house_area, 
                        lessor, legal_representative, person_in_charge, contact_phone, 
                        lessee, tenant, tenant_id, tenant_phone, 
                        start_date, end_date, status, payment_method, 
                        monthly_rent, quarterly_rent, total_rent, annual_rent, deposit, 
                        usage, utility_method, water_fee, electricity_fee, remarks) 
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
                        batch_data
                    )
                    created_count += len(batch_data)
                except Exception as e:
                    logger.warning(f"插入剩余合同数据失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 个合同数据")
            
        except Exception as e:
            logger.error(f"生成合同数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_rent_records(self, per_contract: int):
        """
        为每个合同生成租金记录，严格确保已收租金不超过年租金和合同总租金
        
        Args:
            per_contract: 每个合同生成的租金记录数量
        """
        try:
            logger.info(f"为每个合同生成 {per_contract} 条租金记录...")
            
            # 获取所有合同，包括年租金和总租金字段
            self.cursor.execute("SELECT id, contract_no, lessee, tenant, start_date, end_date, monthly_rent, payment_method, annual_rent, total_rent FROM contracts")
            contracts = self.cursor.fetchall()
            
            if not contracts:
                logger.error("无法生成租金记录，没有找到合同数据")
                return
            
            created_count = 0
            batch_data = []
            
            for contract in contracts:
                # 确定为这个合同生成多少条记录
                actual_records = random.randint(1, per_contract)
                
                # 根据合同的付款方式和时间计算租金周期
                start_date = dt.strptime(contract[4], "%Y-%m-%d")
                end_date = dt.strptime(contract[5], "%Y-%m-%d")
                
                # 租金周期（天）
                if contract[7] == '月付':
                    period_days = 30
                elif contract[7] == '季付':
                    period_days = 90
                elif contract[7] == '半年付':
                    period_days = 180
                elif contract[7] == '年付':
                    period_days = 365
                else:
                    period_days = 30  # 默认月付
                
                # 跟踪已生成的租金总额，确保不超过年租金或总租金
                accumulated_rent = 0
                annual_rent = contract[8]  # 年租金
                total_contract_rent = contract[9]  # 合同总租金
                
                # 计算合同的理论最大可收租金（取年租金和合同总租金中的较小值）
                max_payable_rent = min(annual_rent, total_contract_rent * 0.9)  # 预留10%的余量，避免边界情况
                
                # 生成租金记录
                current_date = start_date
                for i in range(actual_records):
                    # 计算本期开始和结束日期
                    period_start = current_date.strftime("%Y-%m-%d")
                    period_end = (current_date + timedelta(days=period_days-1)).strftime("%Y-%m-%d")
                    
                    # 确保不超过合同结束日期
                    if period_end > contract[5]:
                        break
                    
                    # 收款日期（通常在周期开始后几天到几个月）
                    receipt_days = random.randint(1, 60)
                    receipt_date = (current_date + timedelta(days=receipt_days)).strftime("%Y-%m-%d")
                    
                    # 计算理论金额
                    if contract[7] == '月付':
                        theoretical_amount = contract[6]
                    elif contract[7] == '季付':
                        theoretical_amount = round(contract[6] * 3, 2)
                    elif contract[7] == '半年付':
                        theoretical_amount = round(contract[6] * 6, 2)
                    elif contract[7] == '年付':
                        theoretical_amount = round(contract[6] * 12, 2)
                    else:
                        theoretical_amount = contract[6]
                    
                    # 随机选择账户
                    account = random.choice(self.bank_accounts) if random.random() > 0.2 else None  # 20%概率不填账户
                    
                    # 发票日期（可能为空）
                    invoice_date = None
                    if random.random() > 0.3:  # 70%概率有发票
                        invoice_days = random.randint(0, 15)
                        invoice_date = (dt.strptime(receipt_date, "%Y-%m-%d") + timedelta(days=invoice_days)).strftime("%Y-%m-%d")
                    
                    # 描述
                    description = f"{period_start}至{period_end}租金"
                    
                    # 付款状态
                    today = dt.now().strftime("%Y-%m-%d")
                    
                    # 计算剩余可收租金
                    remaining_rent = max_payable_rent - accumulated_rent
                    
                    # 如果没有剩余可收租金，只生成未结清状态的记录
                    if remaining_rent <= 0:
                        payment_status = '未结清'
                        amount = theoretical_amount  # 保持理论金额，但不影响累计
                    else:
                        # 正常状态逻辑，但调整概率以减少超额风险
                        if receipt_date <= today:
                            # 已过收款日期，可能已结清
                            if random.random() > 0.4:  # 降低已结清概率到60%
                                payment_status = '已结清'
                                # 直接使用理论金额，但确保不超过剩余可收租金
                                amount = min(theoretical_amount, remaining_rent)
                            elif random.random() > 0.5:  # 10%概率部分结清
                                payment_status = '部分结清'
                                # 确保部分金额大于0且不超过原金额和剩余可收租金
                                partial_ratio = random.uniform(0.2, 0.8)
                                amount = min(round(theoretical_amount * partial_ratio, 2), remaining_rent)
                            else:  # 30%概率已逾期（增加逾期概率）
                                payment_status = '已逾期'
                                amount = theoretical_amount  # 保持理论金额，但不影响累计
                        else:
                            # 未到收款日期
                            payment_status = '未结清'
                            amount = theoretical_amount  # 保持理论金额，但不影响累计
                    
                    # 添加边界值（修改为更安全的值）
                    if self.config['include_edge_cases'] and random.random() < self.config['exception_config']['empty_values_ratio']:
                        # 边界值设置为理论金额的较小比例，但不超过剩余可收租金
                        amount = min(max(100.0, theoretical_amount * 0.1), remaining_rent if payment_status in ['已结清', '部分结清'] else amount)
                    
                    # 添加异常值（大幅修改，确保不违反业务规则）
                    if self.config['include_exceptional_cases'] and random.random() < self.config['exception_config']['out_of_range_ratio'] and payment_status in ['已结清', '部分结清']:
                        # 异常金额必须严格小于剩余可收租金，并且限制在合理范围内
                        if remaining_rent > 1000:  # 只在有足够剩余租金时生成异常值
                            # 异常值可以是较低的，但不会超过剩余租金
                            exception_amount = min(remaining_rent * 0.9, round(random.uniform(1000, remaining_rent * 0.8), 2))
                            amount = exception_amount
                    
                    # 确保金额大于0
                    if amount <= 0:
                        amount = 100.0  # 设置一个合理的最小值
                    
                    # 再次检查并调整金额，确保不会超过年租金或合同总租金
                    if payment_status in ['已结清', '部分结清']:
                        # 最终安全检查：确保累计租金不会超过年租金或合同总租金
                        new_accumulated = accumulated_rent + amount
                        if new_accumulated > annual_rent:
                            # 调整金额，确保不超过年租金
                            amount = max(0, annual_rent - accumulated_rent)
                            # 如果调整后金额为0，改变状态
                            if amount == 0:
                                payment_status = '未结清'
                        
                        if accumulated_rent + amount > total_contract_rent:
                            # 调整金额，确保不超过合同总租金
                            amount = max(0, total_contract_rent - accumulated_rent)
                            # 如果调整后金额为0，改变状态
                            if amount == 0:
                                payment_status = '未结清'
                    
                    # 更新累计租金
                    if payment_status in ['已结清', '部分结清']:
                        accumulated_rent += amount
                        # 再次检查，确保累计值正确
                        accumulated_rent = min(accumulated_rent, annual_rent)
                        accumulated_rent = min(accumulated_rent, total_contract_rent)
                    
                    # 添加到批处理数据
                    batch_data.append((
                        contract[1], contract[2], contract[3], receipt_date, amount,
                        period_start, period_end, account, invoice_date, description, payment_status
                    ))
                    
                    # 批量插入
                    if len(batch_data) >= self.config['batch_size']:
                        try:
                            self.cursor.executemany(
                                '''INSERT INTO rent_records 
                                (contract_no, lessee, tenant, receipt_date, amount, 
                                period_start, period_end, account, invoice_date, description, payment_status) 
                                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
                                batch_data
                            )
                            created_count += len(batch_data)
                            batch_data = []
                        except Exception as e:
                            logger.warning(f"批量插入租金记录失败: {str(e)}")
                    
                    # 更新当前日期为下一个周期
                    current_date += timedelta(days=period_days)
            
            # 插入剩余数据
            if batch_data:
                try:
                    self.cursor.executemany(
                        '''INSERT INTO rent_records 
                        (contract_no, lessee, tenant, receipt_date, amount, 
                        period_start, period_end, account, invoice_date, description, payment_status) 
                        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
                        batch_data
                    )
                    created_count += len(batch_data)
                except Exception as e:
                    logger.warning(f"插入剩余租金记录失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 条租金记录")
            
        except Exception as e:
            logger.error(f"生成租金记录时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_notes(self, count: int):
        """
        生成笔记数据
        
        Args:
            count: 笔记数量
        """
        try:
            logger.info(f"生成 {count} 个笔记数据...")
            
            # 预设的一些笔记标题
            note_titles = [
                '房屋交接注意事项', '租户管理规定', '租金收取流程', '合同续签流程',
                '房屋维修申请流程', '水电费结算说明', '紧急联系人清单', '系统操作指南',
                '常见问题解答', '租户投诉处理流程', '房屋检查清单', '合同变更流程',
                '房屋保险说明', '租户退租流程', '新租户入住流程', '房东信息变更流程',
                '消防安全管理', '突发事件处理预案', '房屋设备维护指南', '租金调整政策'
            ]
            
            created_count = 0
            batch_data = []
            
            for i in range(count):
                # 生成唯一的笔记名称
                base_title = random.choice(note_titles)
                # 添加时间戳和随机数确保唯一性
                timestamp = dt.now().strftime("%H%M%S")
                random_id = random.randint(100, 999)
                note_name = self._generate_unique_value('note_name', 
                                                      lambda: f"{base_title}-{timestamp}-{random_id}")
                
                # 生成创建时间（过去1年内）
                created_at = (dt.now() - timedelta(days=random.randint(1, 365))).strftime("%Y-%m-%d %H:%M:%S")
                
                # 生成更新时间（在创建时间之后，可能就是创建时间）
                days_after_created = random.randint(0, (dt.now() - dt.strptime(created_at[:10], "%Y-%m-%d")).days)
                updated_at = (dt.strptime(created_at, "%Y-%m-%d %H:%M:%S") + timedelta(days=days_after_created)).strftime("%Y-%m-%d %H:%M:%S")
                
                # 生成笔记内容
                content = f"这是 {note_name} 的详细内容。\n\n"
                content += f"创建于: {created_at}\n"
                content += f"更新于: {updated_at}\n\n"
                content += "本文档包含相关的政策规定和操作流程说明。\n"
                content += "请相关人员严格按照流程执行，确保管理工作的规范性。\n"
                content += "如有疑问，请联系管理员。\n"
                
                # 随机添加一些额外内容
                if random.random() > 0.5:
                    content += f"\n备注: {random.randint(1, 1000)}"
                
                # 添加异常数据
                if self.config['include_exceptional_cases'] and random.random() < self.config['exception_config']['invalid_format_ratio']:
                    content = "\x00\x01\x02特殊字符测试\x03\x04"
                
                # 添加到批处理数据
                batch_data.append((note_name, content, created_at, updated_at))
                
                # 批量插入
                if len(batch_data) >= self.config['batch_size']:
                    try:
                        self.cursor.executemany(
                            "INSERT INTO notes (note_name, content, created_at, updated_at) VALUES (?, ?, ?, ?)",
                            batch_data
                        )
                        created_count += len(batch_data)
                        batch_data = []
                    except Exception as e:
                        logger.warning(f"批量插入笔记数据失败: {str(e)}")
            
            # 插入剩余数据
            if batch_data:
                try:
                    self.cursor.executemany(
                        "INSERT INTO notes (note_name, content, created_at, updated_at) VALUES (?, ?, ?, ?)",
                        batch_data
                    )
                    created_count += len(batch_data)
                except Exception as e:
                    logger.warning(f"插入剩余笔记数据失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 个笔记数据")
            
        except Exception as e:
            logger.error(f"生成笔记数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_system_params(self, count: int):
        """
        生成系统参数数据（新增功能）
        
        Args:
            count: 参数数量
        """
        try:
            logger.info(f"生成 {count} 个系统参数数据...")
            
            created_count = 0
            
            # 预设的系统参数键值对
            param_values = {
                'db_version': '1.8.5',
                'last_backup': dt.now().strftime("%Y-%m-%d %H:%M:%S"),
                'system_name': '租赁合同管理系统',
                'max_file_size': '104857600',  # 100MB
                'backup_interval_days': '7',
                'log_retention_days': '90',
                'max_users': '50',
                'session_timeout_minutes': '30',
                'max_contracts_per_page': '50',
                'default_currency': '¥'
            }
            
            # 选择要插入的参数
            selected_keys = random.sample(self.system_param_keys, min(count, len(self.system_param_keys)))
            
            for key in selected_keys:
                value = param_values.get(key, str(random.randint(1, 1000)))
                
                try:
                    self.cursor.execute(
                        "INSERT OR REPLACE INTO system_params (key, value) VALUES (?, ?)",
                        (key, value)
                    )
                    created_count += 1
                except Exception as e:
                    logger.warning(f"插入系统参数 {key} 失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 个系统参数数据")
            
        except Exception as e:
            logger.error(f"生成系统参数数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_operation_logs(self, count: int):
        """
        生成操作日志数据（新增功能）
        
        Args:
            count: 日志数量
        """
        try:
            logger.info(f"生成 {count} 条操作日志数据...")
            
            # 获取系统中的用户
            self.cursor.execute("SELECT username FROM users")
            users = [u[0] for u in self.cursor.fetchall()]
            if not users:
                users = ['admin', 'user1', 'user2']  # 默认用户
            
            # 获取系统中的合同编号
            self.cursor.execute("SELECT contract_no FROM contracts LIMIT 20")
            contract_nos = [c[0] for c in self.cursor.fetchall()]
            
            created_count = 0
            batch_data = []
            
            for i in range(count):
                # 生成操作时间（过去3个月内）
                log_time = (dt.now() - timedelta(days=random.randint(1, 90))).strftime("%Y-%m-%d %H:%M:%S")
                
                # 随机选择用户
                username = random.choice(users)
                
                # 随机选择操作类型
                operation_type = random.choice(self.operation_types)
                
                # 根据操作类型生成操作内容
                if operation_type in ['新增', '编辑', '删除'] and contract_nos:
                    contract_no = random.choice(contract_nos)
                    operation_content = f"{operation_type}合同 {contract_no}"
                else:
                    operation_content = f"{operation_type}操作"
                
                # 随机操作结果
                operation_result = '成功' if random.random() > 0.1 else '失败'  # 90%成功率
                
                # 生成IP地址
                ip_address = f"192.168.{random.randint(1, 254)}.{random.randint(1, 254)}"
                
                # 详细信息
                detail = f"用户 {username} 执行了 {operation_content}，结果: {operation_result}"
                
                # 添加到批处理数据
                batch_data.append((log_time, None, username, operation_type, operation_content, operation_result, ip_address, detail))
                
                # 批量插入
                if len(batch_data) >= self.config['batch_size']:
                    try:
                        self.cursor.executemany(
                            "INSERT INTO operation_logs (log_time, user_id, username, operation_module, operation_content, operation_result, ip_address, detail) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
                            batch_data
                        )
                        created_count += len(batch_data)
                        batch_data = []
                    except Exception as e:
                        logger.warning(f"批量插入操作日志失败: {str(e)}")
            
            # 插入剩余数据
            if batch_data:
                try:
                    self.cursor.executemany(
                        "INSERT INTO operation_logs (log_time, user_id, username, operation_module, operation_content, operation_result, ip_address, detail) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
                        batch_data
                    )
                    created_count += len(batch_data)
                except Exception as e:
                    logger.warning(f"插入剩余操作日志失败: {str(e)}")
            
            logger.info(f"已成功生成 {created_count} 条操作日志数据")
            
        except Exception as e:
            logger.error(f"生成操作日志数据时发生错误: {str(e)}", exc_info=True)
            raise
    
    def _generate_data_report(self):
        """
        生成数据生成统计报告
        """
        try:
            logger.info("生成数据统计报告...")
            
            report = {}
            tables = ['houses', 'tenants', 'landlords', 'contracts', 'rent_records', 'notes', 'users', 'system_params', 'operation_logs']
            
            for table in tables:
                try:
                    self.cursor.execute(f"SELECT COUNT(*) FROM {table}")
                    count = self.cursor.fetchone()[0]
                    report[table] = count
                except Exception as e:
                    logger.warning(f"统计 {table} 表数据失败: {str(e)}")
                    report[table] = '未知'
            
            # 输出报告
            logger.info("===== 数据生成统计报告 =====")
            for table, count in report.items():
                logger.info(f"{table}: {count}")
            logger.info("==========================")
            
        except Exception as e:
            logger.error(f"生成数据报告时发生错误: {str(e)}")
    
    # 工具方法
    def _generate_unique_value(self, key_type: str, generator_func: Callable) -> str:
        """
        生成唯一值
        
        Args:
            key_type: 值类型，用于在记录集合中查找
            generator_func: 生成值的函数
            
        Returns:
            str: 唯一的值
        """
        max_attempts = 100
        for _ in range(max_attempts):
            value = generator_func()
            if value not in self.generated_values[key_type]:
                self.generated_values[key_type].add(value)
                return value
        
        # 如果无法生成唯一值，添加时间戳
        timestamp = dt.now().strftime("%Y%m%d%H%M%S%f")
        value = f"{generator_func()}_{timestamp}"
        self.generated_values[key_type].add(value)
        return value
    
    def _generate_phone_number(self) -> str:
        """
        生成中国手机号
        
        Returns:
            str: 手机号码
        """
        prefixes = ['130', '131', '132', '133', '134', '135', '136', '137', '138', '139',
                   '150', '151', '152', '153', '155', '156', '157', '158', '159',
                   '170', '171', '172', '173', '175', '176', '177', '178',
                   '180', '181', '182', '183', '184', '185', '186', '187', '188', '189']
        
        prefix = random.choice(prefixes)
        suffix = ''.join([str(random.randint(0, 9)) for _ in range(8)])
        
        return f"{prefix}{suffix}"
    
    def _weighted_random_choice(self, weights: Dict[str, int], fallback_list: List[str] = None) -> str:
        """
        根据权重随机选择
        
        Args:
            weights: 权重字典，如 {'A': 30, 'B': 70}
            fallback_list: 当权重字典为空时的备选列表
            
        Returns:
            str: 选中的值
        """
        if not weights and fallback_list:
            return random.choice(fallback_list)
        
        items = list(weights.keys())
        weights_list = list(weights.values())
        
        # 计算总权重
        total_weight = sum(weights_list)
        if total_weight == 0:
            return random.choice(items)
        
        # 归一化权重
        normalized_weights = [w / total_weight for w in weights_list]
        
        return random.choices(items, weights=normalized_weights, k=1)[0]
    
    def export_config_template(self, output_path: str = 'mock_data_config_template.json'):
        """
        导出配置模板文件
        
        Args:
            output_path: 输出路径
        """
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                json.dump(self.config, f, ensure_ascii=False, indent=2)
            logger.info(f"配置模板已导出到: {output_path}")
        except Exception as e:
            logger.error(f"导出配置模板失败: {str(e)}")


def parse_arguments():
    """
    解析命令行参数
    """
    parser = argparse.ArgumentParser(description='租赁合同管理系统增强版模拟数据生成器')
    
    # 数据库路径
    parser.add_argument('-d', '--db-path', type=str, default=None,
                        help='数据库文件路径，默认为系统默认路径')
    
    # 配置文件路径
    parser.add_argument('-c', '--config', type=str, default=None,
                        help='配置文件路径，使用JSON格式')
    
    # 导出配置模板
    parser.add_argument('--export-config', type=str, default=None,
                        help='导出配置模板到指定文件')
    
    # 是否清除现有数据
    parser.add_argument('--clear', action='store_true',
                        help='是否清除现有的测试数据')
    
    # 生成的数据量
    parser.add_argument('--houses', type=int, default=None,
                        help='生成的房屋数量')
    
    parser.add_argument('--tenants', type=int, default=None,
                        help='生成的租户数量')
    
    parser.add_argument('--contracts', type=int, default=None,
                        help='生成的合同数量')
    
    parser.add_argument('--landlords', type=int, default=None,
                        help='生成的房东数量')
    
    parser.add_argument('--rent-records', type=int, default=None,
                        help='每个合同生成的租金记录数量')
    
    parser.add_argument('--notes', type=int, default=None,
                        help='生成的笔记数量')
    
    parser.add_argument('--users', type=int, default=None,
                        help='生成的用户数量')
    
    # 是否包含边界值和异常数据
    parser.add_argument('--no-edge-cases', action='store_true',
                        help='不包含边界值数据')
    
    parser.add_argument('--no-exceptional-cases', action='store_true',
                        help='不包含异常情况数据')
    
    # 随机种子，用于可重复的测试
    parser.add_argument('--seed', type=int, default=None,
                        help='随机种子，用于生成可重复的测试数据')
    
    # 批处理大小
    parser.add_argument('--batch-size', type=int, default=None,
                        help='批处理大小，用于大数据量生成优化')
    
    return parser.parse_args()


def main():
    """
    主函数
    """
    # 导入必要的库
    import time
    
    # 解析命令行参数
    args = parse_arguments()
    
    # 创建数据生成器
    generator = EnhancedMockDataGenerator(db_path=args.db_path, config_path=args.config)
    
    # 如果需要导出配置模板
    if args.export_config:
        generator.export_config_template(args.export_config)
        print(f"配置模板已导出到: {args.export_config}")
        return
    
    # 准备自定义配置
    custom_config = {}
    
    # 设置是否清除现有数据
    if args.clear:
        custom_config['clear_existing'] = True
    
    # 设置是否包含边界值和异常数据
    if args.no_edge_cases:
        custom_config['include_edge_cases'] = False
    if args.no_exceptional_cases:
        custom_config['include_exceptional_cases'] = False
    
    # 设置随机种子
    if args.seed is not None:
        custom_config['random_seed'] = args.seed
    
    # 设置批处理大小
    if args.batch_size is not None:
        custom_config['batch_size'] = args.batch_size
    
    # 设置数据量
    data_volumes = {}
    if args.houses is not None:
        data_volumes['houses'] = args.houses
    if args.tenants is not None:
        data_volumes['tenants'] = args.tenants
    if args.contracts is not None:
        data_volumes['contracts'] = args.contracts
    if args.landlords is not None:
        data_volumes['landlords'] = args.landlords
    if args.rent_records is not None:
        data_volumes['rent_records_per_contract'] = args.rent_records
    if args.notes is not None:
        data_volumes['notes'] = args.notes
    if args.users is not None:
        data_volumes['users'] = args.users
    
    if data_volumes:
        custom_config['data_volumes'] = data_volumes
    
    # 开始生成数据
    print("开始生成模拟测试数据...")
    start_time = time.time()
    
    success = generator.generate_mock_data(custom_config)
    
    elapsed_time = time.time() - start_time
    
    if success:
        print(f"模拟数据生成完成！总共耗时: {elapsed_time:.2f} 秒")
    else:
        print("模拟数据生成失败，请检查日志了解详情")


if __name__ == "__main__":
    main()
